home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / viewkit / xcontact / parody / parody.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  14.4 KB  |  655 lines

  1. // ---------- parody.c++
  2.  
  3. // ==========================================
  4. // Parody persistent object member functions
  5. // ==========================================
  6.  
  7. #include <new.h>
  8. #include <stdlib.h>
  9. #include "parody.h"
  10. char *getenv(), *home;
  11.  
  12. void NoMemory()
  13. {
  14.     exit(-1);
  15. }
  16.  
  17. // =======================================
  18. // Parody member functions
  19. // =======================================
  20.  
  21. // ---------- construct a Parody database
  22. Parody::Parody(pString name) :
  23.             FileHeader( name + pString(".DAT")),
  24.                 index(name + pString(".NDX"))
  25. {
  26.     set_new_handler(NoMemory);
  27.     rebuildnode = 0;
  28. }
  29.  
  30. // ---------- close the Parody database
  31. Parody::~Parody()
  32. {
  33.     Btree *bt = (Btree *) btrees.FirstListEntry();
  34.     while (bt != NULL)    {
  35.         delete bt;
  36.         bt = (Btree *) btrees.FirstListEntry();
  37.     }
  38.  
  39. }
  40.  
  41. void Parody::Flush()
  42. {
  43.   Parody::~Parody();
  44.   FileHeader::Flush();
  45.   index.Flush();
  46. }
  47.  
  48. // ------- read an object header record
  49. void Parody::GetObjectHeader(
  50.                 ObjAddr nd,ObjectHeader &objhdr)
  51. {
  52.     Node *node = new Node(this, nd);
  53.     nfile.read((char *)&objhdr, sizeof(ObjectHeader));
  54.     delete node;
  55. }
  56.  
  57. void Parody::RebuildIndexes(ObjAddr nd)
  58. {
  59.     rebuildnode = nd;
  60. }
  61.  
  62. // =======================================
  63. // Persistent base class member functions
  64. // =======================================
  65.  
  66. Persistent *Persistent::thispers = NULL;
  67.  
  68. // ------ constructor
  69. Persistent::Persistent(Parody& db, int cid) :
  70.                                 parody(db), objhdr(cid)
  71. {
  72.     oldthispers = thispers;
  73.     thispers = this;
  74.     changed = pFalse;
  75.     deleted = pFalse;
  76.     newobject = pFalse;
  77.     offset = 0;
  78.     indexcount = 0;
  79.     count = 0;
  80.     node = NULL;
  81.     objectlist = NULL;
  82.     objectcopy = NULL;
  83.     objectaddress = 0;
  84. }
  85.  
  86. // ------ destructor
  87. Persistent::~Persistent()
  88. {
  89.     RemoveObject();
  90. }
  91.  
  92. // ------ search the collected Btrees for this key's index
  93. //        add it if it does not exist
  94. Btree *Persistent::FindIndex(Key *key)
  95. {
  96.     Btree *bt = NULL;
  97.     if (key == NULL)
  98.         key = (Key *) keys.FirstListEntry();
  99.     if (key != NULL)    {
  100.         bt = (Btree *) parody.Btrees().FirstListEntry();
  101.         while (bt != NULL)    {
  102.             Key *tkey = bt->NullKey();
  103.             if (tkey->classid == key->classid &&
  104.                     tkey->indexno == key->indexno)
  105.                 break;
  106.             bt = (Btree *) (bt->NextListEntry());
  107.         }
  108.         if (bt == NULL)    {
  109.             // --- key does not have declared Btree index yet
  110.             bt = new Btree(parody.IndexFile(), key);
  111.             bt->AppendListEntry(&parody.Btrees());
  112.         }
  113.     }
  114.     return bt;
  115. }
  116.  
  117. //  ---------------- record the object's state
  118. void Persistent::RecordObject()
  119. {
  120.     // ---- remove this obj in case it was recorded already
  121.     RemoveObject();
  122.     // ---- put the object's address in a parody list of
  123.     //      instantiated objects
  124.     objectlist = new ObjectList(&parody.Objects(), this);
  125.     // ---- make copies of the original keys for later update
  126.     Key *key = (Key *) keys.FirstListEntry();
  127.     while (key != NULL)    {
  128.         Key *ky = key->Make();
  129.         *ky = *key;
  130.         ky->Key::operator=(*key);
  131.         ky->AppendListEntry(&orgkeys);
  132.         // --- instantiate the index b-tree (if not already)
  133.         FindIndex(ky);
  134.         key = (Key *) (key->NextListEntry());
  135.     }
  136. }
  137.  
  138. //  ---- remove the record of the object's state
  139. void Persistent::RemoveObject()
  140. {
  141.     // --- remove object's address from the parody list
  142.     delete objectlist;
  143.     objectlist = NULL;
  144.     // ----- remove copies of the original keys
  145.     Key *ky = (Key *) orgkeys.FirstListEntry();
  146.     while (ky != NULL)    {
  147.         delete ky;
  148.         ky = (Key *) orgkeys.FirstListEntry();
  149.     }
  150. }
  151.  
  152. // -- called from derived constructor after all construction
  153. void Persistent::LoadObject(ObjAddr nd)
  154. {
  155.     thispers = NULL;
  156.     objectaddress = nd;
  157.     if (parody.RebuildingIndexes())
  158.         objectaddress = parody.RebuildNode();
  159.     if (objectaddress == 0)
  160.         // --- position at object's node
  161.         SearchIndex((Key *) keys.FirstListEntry());
  162.     if (objectaddress != 0)    {
  163.         // --- search for a previous instance of this object
  164.         ObjectList *obj =
  165.             (ObjectList *) parody.Objects().FirstListEntry();
  166.         while (obj != NULL)    {
  167.             if (objectaddress == obj->object->objectaddress)  {
  168.                 // ---- object already instantiated
  169.                 objectcopy = obj->object;
  170.                 break;
  171.             }
  172.             obj = (ObjectList *) obj->NextListEntry();
  173.         }
  174.         if (obj == NULL)    {
  175.             PositionNode();
  176.             ReadDataMembers();
  177.         }
  178.     }
  179.     thispers = oldthispers;
  180. }
  181.  
  182. // ------ write the object to the database
  183. void Persistent::ObjectOut()
  184. {
  185.     // --- tell object to write its data members
  186.     Write();
  187.     // --- pad the last node
  188.     int padding = nodedatalength - offset;
  189.     if (padding)    {
  190.         pString pads(padding);
  191.         parody.Nfile().write(pads, padding);
  192.     }
  193.     NodeNbr nx = node->NextNode();
  194.     node->SetNextNode(0);
  195.     delete node;
  196.     node = NULL;
  197.     // --- if node was linked, object got shorter
  198.     while (nx != 0)    {
  199.         Node nd(&parody, nx);
  200.         nx = nd.NextNode();
  201.         nd.MarkNodeDeleted();
  202.     }
  203. }
  204.  
  205. // ----- write the object's node header
  206. void Persistent::WriteObjectHeader()
  207. {
  208.     // --- write the relative node number and class id
  209.     fstream& df = parody.Nfile();
  210.     df.write((char *) &objhdr, sizeof(ObjectHeader));
  211.     offset = sizeof(ObjectHeader);
  212.     objhdr.ndnbr++;
  213. }
  214.  
  215. // ----- write the object's node header
  216. void Persistent::ReadObjectHeader()
  217. {
  218.     // --- write the relative node number and class id
  219.     fstream& df = parody.Nfile();
  220.     df.read((char *) &objhdr, sizeof(ObjectHeader));
  221.     offset = sizeof(ObjectHeader);
  222. }
  223.  
  224. // --- called from derived destructor before all destruction
  225. //        a new or existing object is being saved
  226. void Persistent::SaveObject()
  227. {
  228.     if (parody.RebuildingIndexes())
  229.         AddIndexes();
  230.     else if (newobject)    {
  231.         if (!deleted && ObjectExists())    {
  232.             PositionNode();
  233.             AddIndexes();
  234.             ObjectOut();
  235.             RecordObject();
  236.         }
  237.     }
  238.     else if (deleted || changed)    {
  239.         if (!ObjectExists())
  240.             return;
  241.         // --- position the parody file at the object's node
  242.         PositionNode();
  243.         if (deleted)    {
  244.             // --- delete the object's nodes from the database
  245.             while (node != NULL)    {
  246.                 node->MarkNodeDeleted();
  247.                 NodeNbr nx = node->NextNode();
  248.                 delete node;
  249.                 if (nx)
  250.                     node = new Node(&parody, nx);
  251.                 else
  252.                     node = NULL;
  253.             }
  254.             DeleteIndexes();
  255.         }
  256.         else    {
  257.             // --- tell object to write its data members
  258.             ObjectOut();
  259.             // ---- update the object's indexes
  260.             UpdateIndexes();
  261.             RecordObject();
  262.         }
  263.     }
  264. }
  265.  
  266. // --- read one data member of the object from the database
  267. void Persistent::ReadObject(void *buf, int length)
  268. {
  269.     fstream& df = parody.Nfile();
  270.     while (node != NULL && length > 0)    {
  271.         if (offset == nodedatalength)    {
  272.             NodeNbr nx = node->NextNode();
  273.             delete node;
  274.             node = nx ? new Node(&parody, nx) : NULL;
  275.             ReadObjectHeader();
  276.         }
  277.         if (node != NULL)    {
  278.             int len = min(length, nodedatalength-offset);
  279.             df.read((char *)buf, len);
  280.             buf = (char *)buf + len;
  281.             offset += len;
  282.             length -= len;
  283.         }
  284.     }
  285. }
  286.  
  287. // --- write one data member of the object to the database
  288. void Persistent::WriteObject(void *buf, int length)
  289. {
  290.     fstream& df = parody.Nfile();
  291.     while (node != NULL && length > 0)    {
  292.         if (offset == nodedatalength)    {
  293.             NodeNbr nx = node->NextNode();
  294.             if (nx == 0)
  295.                 nx = parody.NewNode();
  296.             node->SetNextNode(nx);
  297.             delete node;
  298.             node = new Node(&parody, nx);
  299.             WriteObjectHeader();
  300.         }
  301.         int len = min(length, nodedatalength-offset);
  302.         df.write((char *)buf, len);
  303.         buf = (char *)buf + len;
  304.         offset += len;
  305.         length -= len;
  306.     }
  307. }
  308.  
  309. // ------------ read a string
  310. void Persistent::ReadObject(pString& str)
  311. {
  312.     int len;
  313.     ReadObject(&len, sizeof(int));
  314.     pString s(len);
  315.     ReadObject((char *)s, len);
  316.     str = s;
  317. }
  318.  
  319. // ------------ write a string
  320. void Persistent::WriteObject(pString& str)
  321. {
  322.     int len = str.Strlen();
  323.     WriteObject(&len, sizeof(int));
  324.     WriteObject((char *)str, len);
  325. }
  326.  
  327. // ---- add the index values to the object's index btrees
  328. void Persistent::AddIndexes()
  329. {
  330.     Key *key = (Key *) keys.FirstListEntry();
  331.     while (key != NULL)    {
  332.         Btree *bt = FindIndex(key);
  333.         key->fileaddr = objectaddress;
  334.         bt->Insert(key);
  335.         key = (Key *) (key->NextListEntry());
  336.     }
  337. }
  338.  
  339. // ---- update the index values in the object's index btrees
  340. void Persistent::UpdateIndexes()
  341. {
  342.     Key *oky = (Key *) orgkeys.FirstListEntry();
  343.     Key *key = (Key *) keys.FirstListEntry();
  344.     while (key != NULL)    {
  345.         if (!(*oky == *key))    {
  346.             // --- key value has changed, update the index
  347.             // --- delete the old
  348.             Btree *bt = FindIndex(oky);
  349.             oky->fileaddr = objectaddress;
  350.             bt->Delete(oky);
  351.             // --- insert the new
  352.             key->fileaddr = objectaddress;
  353.             bt->Insert(key);
  354.         }
  355.         oky = (Key *) (oky->NextListEntry());
  356.         key = (Key *) (key->NextListEntry());
  357.     }
  358. }
  359.  
  360. // -- delete the index values from the object's index btrees
  361. void Persistent::DeleteIndexes()
  362. {
  363.     Key *key = (Key *) orgkeys.FirstListEntry();
  364.     while (key != NULL)    {
  365.         Btree *bt = FindIndex(key);
  366.         key->fileaddr = objectaddress;
  367.         bt->Delete(key);
  368.         key = (Key *) (key->NextListEntry());
  369.     }
  370. }
  371.  
  372. // ----- position the file to the specifed node number
  373. void Persistent::PositionNode()
  374. {
  375.     if (objectaddress)    {
  376.         node = new Node(&parody, (NodeNbr) objectaddress);
  377.         offset = sizeof(ObjectHeader);
  378.         fstream& nf = parody.Nfile();
  379.         ObjectHeader oh;
  380.         nf.read((char *)&oh, sizeof(ObjectHeader));
  381.         nf.seekp(nf.tellg());
  382.         if (oh.classid != objhdr.classid || oh.ndnbr != 0)
  383.             objectaddress = 0;
  384.     }
  385. }
  386.  
  387. // ------- search the index for a match on the key
  388. void Persistent::SearchIndex(Key *key)
  389. {
  390.     objectaddress = 0;
  391.     if (key != NULL && !key->isNullValue())    {
  392.         Btree *bt = FindIndex(key);
  393.         if (bt != NULL && bt->Find(key))    {
  394.             if (key->indexno != 0)    {
  395.                 Key *bc;
  396.                 do
  397.                     bc = bt->Previous();
  398.                 while (bc != NULL && *bc == *key);
  399.                 key = bt->Next();
  400.             }
  401.             objectaddress = key->fileaddr;
  402.         }
  403.     }
  404. }
  405.  
  406. // --------- find an object by a key value
  407. void Persistent::FindObject(Key *key)
  408. {
  409.     SearchIndex(key);
  410.     PositionNode();
  411.     ReadDataMembers();
  412. }
  413.  
  414. // --- scan nodes forward to the first one of next object
  415. void Persistent::ScanForward(NodeNbr nd)
  416. {
  417.     ObjectHeader oh;
  418.     while (++nd < parody.HighestNode())    {
  419.         parody.GetObjectHeader(nd, oh);
  420.         if (oh.classid == objhdr.classid && oh.ndnbr == 0)    {
  421.             objectaddress = nd;
  422.             break;
  423.         }
  424.     }
  425. }
  426.  
  427. // --- scan nodes back to first one of the previous object
  428. void Persistent::ScanBackward(NodeNbr nd)
  429. {
  430.     ObjectHeader oh;
  431.     while (--nd > 0)    {
  432.         parody.GetObjectHeader(nd, oh);
  433.         if (oh.classid == objhdr.classid && oh.ndnbr == 0)    {
  434.             objectaddress = nd;
  435.             break;
  436.         }
  437.     }
  438. }
  439.  
  440. // --- retrieve the first object in a key sequence
  441. void Persistent::FirstObject(Key *key)
  442. {
  443.     objectaddress = 0;
  444.     Btree *bt = FindIndex(key);
  445.     if (bt == NULL)
  446.         // ----- keyless object
  447.         ScanForward(0);
  448.     else if ((key = bt->First()) != NULL)
  449.         objectaddress = key->fileaddr;
  450.     if (objectaddress != 0)    {
  451.         PositionNode();
  452.         ReadDataMembers();
  453.     }
  454. }
  455.  
  456. // --- retrieve the last object in a key sequence
  457. void Persistent::LastObject(Key *key)
  458. {
  459.     objectaddress = 0;
  460.     Btree *bt = FindIndex(key);
  461.     if (bt == NULL)
  462.         // ----- keyless object
  463.         ScanBackward(parody.HighestNode());
  464.     else if ((key = bt->Last()) != NULL)
  465.         objectaddress = key->fileaddr;
  466.     if (objectaddress != 0)    {
  467.         PositionNode();
  468.         ReadDataMembers();
  469.     }
  470. }
  471.  
  472. // --- retrieve the next object in a key sequence
  473. void Persistent::NextObject(Key *key)
  474. {
  475.     ObjAddr oa = objectaddress;
  476.     objectaddress = 0;
  477.     Btree *bt = FindIndex(key);
  478.     if (bt == NULL)
  479.         // ----- keyless object
  480.         ScanForward(oa);
  481.     else if ((key = bt->Next()) != NULL)
  482.         objectaddress = key->fileaddr;
  483.     if (objectaddress != 0)    {
  484.         PositionNode();
  485.         ReadDataMembers();
  486.     }
  487. }
  488.  
  489. //UMESH 
  490. // read in the current object
  491. void Persistent::CurrentObject(Key *key)
  492. {
  493.         ObjAddr oa = objectaddress;
  494.         objectaddress = 0;
  495.         Btree *bt = FindIndex(key);
  496.         if (bt == NULL)
  497.                 // ----- keyless object
  498.                 ScanForward(oa);
  499.         else if ((key = bt->Current()) != NULL)
  500.                 objectaddress = key->fileaddr;
  501.         if (objectaddress != 0) {
  502.                 PositionNode();
  503.                 ReadDataMembers();
  504.         }
  505. }
  506.  
  507. // --- retrieve the previous object in a key sequence
  508. void Persistent::PreviousObject(Key *key)
  509. {
  510.     ObjAddr oa = objectaddress;
  511.     objectaddress = 0;
  512.     Btree *bt = FindIndex(key);
  513.     if (bt == NULL)
  514.         // ----- keyless object
  515.         ScanBackward(oa);
  516.     else if ((key = bt->Previous()) != NULL)
  517.         objectaddress = key->fileaddr;
  518.     if (objectaddress != 0)    {
  519.         PositionNode();
  520.         ReadDataMembers();
  521.     }
  522. }
  523.  
  524. // ------- read an object's data members
  525. void Persistent::ReadDataMembers()
  526. {
  527.     if (objectaddress != 0)    {
  528.         // --- tell object to read its data members
  529.         Read();
  530.         delete node;
  531.         node = NULL;
  532.         // --- put the secondary keys into the table
  533.         RecordObject();
  534.     }
  535. }
  536.  
  537. // -------- add an object to the Parody database
  538. pBool Persistent::AddObject()
  539. {
  540.     newobject =
  541.         (pBool) (objectaddress == 0 && TestRelationships());
  542.     if (newobject)    {
  543.         delete node;  // (just in case)
  544.         node = new Node(&parody, parody.NewNode());
  545.         objectaddress = node->GetNodeNbr();
  546.         WriteObjectHeader();
  547.     }
  548.     return newobject;
  549. }
  550.  
  551. // ---------- mark a persistent object for change
  552. pBool Persistent::ChangeObject()
  553. {
  554.     changed = TestRelationships();
  555.     return changed;
  556. }
  557.  
  558. // ---------- mark a persistent object for delete
  559. pBool Persistent::DeleteObject()
  560. {
  561.   Key *key = (Key *) keys.FirstListEntry();
  562.  
  563.   if ( key ) {
  564.  
  565.     Key *ky = key->Make();
  566.     *ky = *key;
  567.     ky->Key::operator=(*key);
  568.  
  569.     if (!ky->isNullValue())    {
  570.         // --- scan for other objects related to this one
  571.         Btree *bt = (Btree*) parody.Btrees().FirstListEntry();
  572.         while (bt != NULL)    {
  573.             Key *tkey = bt->NullKey();
  574.             if (tkey->relatedclass == ky->classid)    {
  575.                 ky->Key::operator=(*tkey);
  576.                 if (bt->Find(ky) == pTrue)    {
  577.                     // --- another object is related, 
  578.                     //     so the delete is rejected
  579.                     delete ky;
  580.                     return pFalse;
  581.                 }
  582.             }
  583.             bt = (Btree *) (bt->NextListEntry());
  584.         }
  585.     }
  586.     delete ky;
  587.   }
  588.  
  589.   deleted = pTrue;
  590.   return deleted;
  591. }
  592.  
  593. // ------ test an object's relationships
  594. //        return false if it is related to a 
  595. //        nonexistent object
  596. pBool Persistent::TestRelationships()
  597. {
  598.     Key *key = (Key *) keys.FirstListEntry();
  599.     while (key != NULL)    {
  600.         Key *ky = key->Make();
  601.         *ky = *key;
  602.         ky->Key::operator=(*key);
  603.         if (!ky->isNullValue())    {
  604.             if (ky->relatedclass != -1)    {
  605.                 ky->indexno = 0;
  606.                 ky->classid = ky->relatedclass;
  607.                 ky->fileaddr = 0;
  608.                 Btree *bt = FindIndex(ky);
  609.                 if (bt->Find(ky) ==pFalse)
  610.                     break;
  611.             }
  612.         }
  613.         delete ky;
  614.         key = (Key *) (key->NextListEntry());
  615.     }
  616.     return (pBool) (key == NULL);
  617. }
  618.  
  619. // =====================================
  620. // Handle class (Handle)
  621. // =====================================
  622. Handle::Handle(Handle& handle)
  623. {
  624.     body = handle.body;
  625.     body->count++;
  626. }
  627.  
  628. Handle::~Handle()
  629. {
  630.     if (--body->count == 0)
  631.         delete body;
  632. }
  633.  
  634. Handle& Handle::operator=(Handle& empl)
  635. {
  636.     if (--body->count == 0)
  637.         delete body;
  638.     body = empl.body;
  639.     body->count++;
  640.     return *this;
  641. }
  642.  
  643. void Handle::ConstructBody(Persistent *pbody)
  644. {
  645.     if (pbody->objectcopy != NULL)    {
  646.         // --- LoadObject found another instantiated
  647.         //     copy of the object
  648.         body = pbody->objectcopy;
  649.         delete pbody;
  650.     }
  651.     else 
  652.         body = pbody;
  653.     body->count++;
  654. }
  655.